package net.scribblemedia.candle.data.pattern;

import static java.lang.Math.abs;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static net.scribblemedia.candle.data.pattern.CandleStickType.BLACK_CANDLE;
import static net.scribblemedia.candle.data.pattern.CandleStickType.DOJI_DRAGONFLY;
import static net.scribblemedia.candle.data.pattern.CandleStickType.DOJI_GRAVESTONE;
import static net.scribblemedia.candle.data.pattern.CandleStickType.DOJI_LONGSHADOW;
import static net.scribblemedia.candle.data.pattern.CandleStickType.HAMMER;
import static net.scribblemedia.candle.data.pattern.CandleStickType.HAMMER_INVERTED;
import static net.scribblemedia.candle.data.pattern.CandleStickType.LONG_LOWER;
import static net.scribblemedia.candle.data.pattern.CandleStickType.LONG_UPPER;
import static net.scribblemedia.candle.data.pattern.CandleStickType.MARUBOZU_BLACK;
import static net.scribblemedia.candle.data.pattern.CandleStickType.MARUBOZU_WHITE;
import static net.scribblemedia.candle.data.pattern.CandleStickType.TOP_BLACK;
import static net.scribblemedia.candle.data.pattern.CandleStickType.TOP_WHITE;
import static net.scribblemedia.candle.data.pattern.CandleStickType.UNKNOWN;
import static net.scribblemedia.candle.data.pattern.CandleStickType.WHITE_CANDLE;

import org.encog.ml.data.market.MarketDataType;
import org.encog.ml.data.market.loader.LoadedMarketData;

public class CandleStick {

	public static final double EQUAL_PRECISION = 0.01;

	private double open;
	private double close;
	private double high;
	private double low;
	private double bodyTop;
	private double bodyBottom;

	public CandleStick(LoadedMarketData data) {
		this.open = data.getData(MarketDataType.OPEN);
		this.close = data.getData(MarketDataType.CLOSE);
		this.high = data.getData(MarketDataType.HIGH);
		this.low = data.getData(MarketDataType.LOW);
		this.bodyTop = max(this.open, this.close);
		this.bodyBottom = min(this.open, this.close);
	}

	public CandleStickType determineType() {
		if (isMarubozuBlack()) {
			return MARUBOZU_BLACK;
		} else if (isMarubozuWhite()) {
			return MARUBOZU_WHITE;
		} else if (isLongUpper()) {
			return LONG_UPPER;
		} else if (isLongLower()) {
			return LONG_LOWER;
		} else if (isTopWhite()) {
			return TOP_WHITE;
		} else if (isTopBlack()) {
			return TOP_BLACK;
		} else if (isWhiteCandle()) {
			return WHITE_CANDLE;
		} else if (isBlackCandle()) {
			return BLACK_CANDLE;
		} else if (isDojiLongShadow()) {
			return DOJI_LONGSHADOW;
		} else if (isDojiGraveStone()) {
			return DOJI_GRAVESTONE;
		} else if (isDojiDragonfly()) {
			return DOJI_DRAGONFLY;
		} else if (isHammer()) {
			return HAMMER;
		} else if (isInvertedHammer()) {
			return HAMMER_INVERTED;
		}
		return UNKNOWN;
	}

	public boolean isBlackCandle() {
		return (hasBody() && hasUpperShadow() && hasLowerShadow() && isBlack());
	}

	public boolean isWhiteCandle() {
		return (hasBody() && hasUpperShadow() && hasLowerShadow() && isBlack());
	}

	public boolean isDoji() {
		return (!hasBody() && hasUpperShadow() && hasLowerShadow());
	}

	public boolean isDojiGraveStone() {
		return (!hasBody() && hasUpperShadow() && !hasLowerShadow());
	}

	public boolean isDojiDragonfly() {
		return (!hasBody() && !hasUpperShadow() && hasLowerShadow());
	}

	public boolean isDojiLongShadow() {
		return (!hasBody() && hasLongLowerShadow() && hasLongUpperShadow());
	}

	public boolean isHammer() {
		return (isWhite() && hasSmallBody() && !hasUpperShadow() && hasLowerShadow());
	}

	public boolean isInvertedHammer() {
		return (isBlack() && hasSmallBody() && hasUpperShadow() && !hasLowerShadow());
	}

	public boolean isLongLower() {
		return (isWhite() && hasLongLowerShadow() && !hasLongUpperShadow()
				&& hasBody() && !hasSmallBody() && hasUpperShadow() && hasLowerShadow());
	}

	public boolean isLongUpper() {
		return (isBlack() && !hasLongLowerShadow() && hasLongUpperShadow()
				&& hasBody() && !hasSmallBody() && hasUpperShadow() && hasLowerShadow());
	}

	public boolean isMarubozuWhite() {
		return (isWhite() && hasBody() && !hasLowerShadow() && !hasUpperShadow());
	}

	public boolean isMarubozuBlack() {
		return (isBlack() && hasBody() && !hasLowerShadow() && !hasUpperShadow());
	}

	public boolean isTopBlack() {
		return isBlackCandle() && hasSmallBody();
	}

	public boolean isTopWhite() {
		return isWhiteCandle() && hasSmallBody();
	}

	public boolean hasSmallBody() {
		return (abs(this.open - this.close) < 1.0);
	}

	public boolean hasLowerShadow() {
		return ((this.bodyBottom - this.low) > EQUAL_PRECISION);
	}

	public boolean hasUpperShadow() {
		return ((this.high - this.bodyTop) > EQUAL_PRECISION);
	}

	public boolean hasBody() {
		return (abs(this.open - this.close) > EQUAL_PRECISION);
	}

	public boolean isWhite() {
		return this.close > this.open;
	}

	public boolean isBlack() {
		return !isWhite();
	}

	public double getLowerShadowLength() {
		return this.high - this.bodyTop;
	}

	public double getUpperShadowLength() {
		return this.bodyBottom - this.low;
	}

	public boolean hasLongLowerShadow() {
		return (getLowerShadowLength() > (getUpperShadowLength() * 2));
	}

	public boolean hasLongUpperShadow() {
		return (getUpperShadowLength() > (getUpperShadowLength() * 2));
	}
}